#ifndef VEC_H_
#define VEC_H_

#include <cmath>

namespace Sim
{
	class Vector
	{
		double m_x;
		double m_y;
		double m_z;

	public:
		Vector():m_x(0.0),m_y(0.0),m_z(0.0){}
		Vector(double _x, double _y, double _z = 0.0):m_x(_x),m_y(_y),m_z(_z){}

		inline void operator()(double _x, double _y, double _z);
        
        inline Vector& operator=(const Vector& rhs);

		inline double x() const { return m_x; }
		inline void x(double _x) { m_x = _x; }

		inline double y() const { return m_y; }
		inline void y(double _y) { m_y = _y; }
		
		inline double z() const { return m_z; }
		inline void z(double _z) { m_z = _z; }

		inline double mag() const;
		inline Vector unit() const;
	};

	inline void Vector::operator()(double _x, double _y, double _z)
	{
		m_x = _x;
		m_y = _y;
		m_z = _z;
	}

    inline Vector& Vector::operator=(const Vector& rhs)
    {
        if(this != &rhs)
        {
            m_x = rhs.m_x;
            m_y = rhs.m_y;
            m_z = rhs.m_z;
        }
        
        return *this;
    }

	inline Vector operator+(const Vector& _a , const Vector& _b )
	{
		return Vector( _a.x() + _b.x(),
			           _a.y() + _b.y(),
					   _a.z() + _b.z() );
	}

	inline Vector operator-(const Vector& _a , const Vector& _b )
	{
		return Vector( _a.x() - _b.x(),
			           _a.y() - _b.y(),
					   _a.z() - _b.z() );
	}

	inline double operator*(const Vector& _a , const Vector& _b )
	{
		return _a.x() * _b.x() + _a.y() * _b.y() + _a.z() * _b.z();
	}

	inline Vector operator-( const Vector& v )
	{
		return Vector( -v.x(),
			           -v.y(),
					   -v.z() );
	}

	inline Vector operator*( const double _scalar, const Vector& _v )
	{
		return Vector( _scalar * _v.x(),
			           _scalar * _v.y(),
					   _scalar * _v.z() );
	}

	inline Vector operator*( const Vector& _v, const double _scalar )
	{
		return Vector( _scalar * _v.x(),
			           _scalar * _v.y(),
					   _scalar * _v.z() );
	}

	inline Vector operator/( const Vector& _v, const double _scalar )
	{
		return Vector( _v.x() / _scalar,
			           _v.y() / _scalar,
					   _v.z() / _scalar );
	}	


	inline double Vector::mag() const
	{
		return sqrt( m_x * m_x + m_y * m_y + m_z * m_z );
	}

	inline Vector Vector::unit() const
	{
		double recip_vmag = double( 1.0 / mag() );
		return Vector( m_x * recip_vmag , m_y * recip_vmag , m_z * recip_vmag );
	}

	inline Vector cross( const Vector& a , const Vector& b )
	{
		return Vector( a.y()*b.z() - a.z()*b.y(),
			           a.z()*b.x() - a.x()*b.z(),
					   a.x()*b.y() - a.y()*b.x() );
	}

}

#endif